home *** CD-ROM | disk | FTP | other *** search
- /*
- ***** BEGIN LICENSE BLOCK *****
-
- Copyright (c) 2006 Center for History and New Media
- George Mason University, Fairfax, Virginia, USA
- http://chnm.gmu.edu
-
- Licensed under the Educational Community License, Version 1.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.opensource.org/licenses/ecl1.php
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- ***** END LICENSE BLOCK *****
- */
-
- const ZOTERO_AC_CONTRACTID = '@mozilla.org/autocomplete/search;1?name=zotero';
- const ZOTERO_AC_CLASSNAME = 'Zotero AutoComplete';
- const ZOTERO_AC_CID = Components.ID('{06a2ed11-d0a4-4ff0-a56f-a44545eee6ea}');
-
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cr = Components.results;
-
-
- /*
- * Implements nsIAutoCompleteResult
- */
- function ZoteroAutoCompleteResult(searchString, searchResult, defaultIndex,
- errorDescription, results, comments){
- this._searchString = searchString;
- this._searchResult = searchResult;
- this._defaultIndex = defaultIndex;
- this._errorDescription = errorDescription;
- this._results = results;
- this._comments = comments;
- }
-
-
- ZoteroAutoCompleteResult.prototype = {
- _searchString: "",
- _searchResult: 0,
- _defaultIndex: 0,
- _errorDescription: "",
- _results: [],
- _comments: [],
- get searchString(){ return this._searchString; },
- get searchResult(){ return this._searchResult; },
- get defaultIndex(){ return this._defaultIndex; },
- get errorDescription(){ return this._errorDescription; },
- get matchCount(){ return this._results.length; }
- }
-
-
- ZoteroAutoCompleteResult.prototype.getCommentAt = function(index){
- return this._comments[index];
- }
-
-
- ZoteroAutoCompleteResult.prototype.getStyleAt = function(index){
- return null;
- }
-
-
- ZoteroAutoCompleteResult.prototype.getValueAt = function(index){
- return this._results[index];
- }
-
-
- ZoteroAutoCompleteResult.prototype.removeValueAt = function(index){
- this._results.splice(index, 1);
- this._comments.splice(index, 1);
- }
-
-
- ZoteroAutoCompleteResult.prototype.QueryInterface = function(iid){
- if (!iid.equals(Ci.nsIAutoCompleteResult) &&
- !iid.equals(Ci.nsISupports)){
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
- return this;
- }
-
-
-
-
- /*
- * Implements nsIAutoCompleteSearch
- */
- function ZoteroAutoComplete(){
- // Get the Zotero object
- this._zotero = Components.classes["@zotero.org/Zotero;1"]
- .getService(Components.interfaces.nsISupports)
- .wrappedJSObject;
- }
-
-
- ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam,
- previousResult, listener){
-
- this.stopSearch();
-
- /*
- this._zotero.debug("Starting autocomplete search of type '"
- + searchParam + "'" + " with string '" + searchString + "'");
- */
-
- var results = [];
- var comments = [];
-
- // Allow extra parameters to be passed in
- var pos = searchParam.indexOf('/');
- if (pos!=-1){
- var extra = searchParam.substr(pos + 1);
- var searchParam = searchParam.substr(0, pos);
- }
-
- var searchParts = searchParam.split('-');
- searchParam = searchParts[0];
-
- switch (searchParam){
- case '':
- break;
-
- case 'tag':
- var sql = "SELECT tag FROM tags WHERE tag LIKE ?";
- var sqlParams = [searchString + '%'];
- if (extra){
- sql += " AND tagID NOT IN (SELECT tagID FROM itemTags WHERE "
- + "itemID = ?)";
- sqlParams.push(extra);
- }
- sql += " ORDER BY tag";
- var results = this._zotero.DB.columnQuery(sql, sqlParams);
- break;
-
- case 'creator':
- // Valid fieldMode values:
- // 0 == search two-field creators
- // 1 == search single-field creators
- // 2 == search both
- var [fieldMode, itemID] = extra.split('-');
-
- if (fieldMode==2)
- {
- var sql = "SELECT DISTINCT CASE fieldMode WHEN 1 THEN lastName "
- + "WHEN 0 THEN firstName || ' ' || lastName END AS name "
- + "FROM creators WHERE CASE fieldMode "
- + "WHEN 1 THEN lastName "
- + "WHEN 0 THEN firstName || ' ' || lastName END "
- + "LIKE ? ORDER BY name";
- var sqlParams = searchString + '%';
- }
- else
- {
- var sql = "SELECT DISTINCT ";
- if (fieldMode==1){
- sql += "lastName AS name, creatorID || '-1' AS creatorID";
- }
- // Retrieve the matches in the specified field
- // as well as any full names using the name
- //
- // e.g. "Shakespeare" and "Shakespeare, William"
- //
- // creatorID is in the format "12345-1" or "12345-2",
- // - 1 means the row uses only the specified field
- // - 2 means it uses both
- else {
- sql += "CASE WHEN firstName='' OR firstName IS NULL THEN lastName "
- + "ELSE lastName || ', ' || firstName END AS name, "
- + "creatorID || '-' || CASE "
- + "WHEN (firstName = '' OR firstName IS NULL) THEN 1 "
- + "ELSE 2 END AS creatorID";
- }
-
- var fromSQL = " FROM creators WHERE " + searchParts[2]
- + " LIKE ?1 " + "AND fieldMode=?2";
- var sqlParams = [searchString + '%', parseInt(fieldMode)];
- if (itemID){
- fromSQL += " AND creatorID NOT IN (SELECT creatorID FROM "
- + "itemCreators WHERE itemID=?3)";
- sqlParams.push(itemID);
- }
-
- sql += fromSQL;
-
- // If double-field mode, include matches for just this field
- // as well (i.e. "Shakespeare"), and group to collapse repeats
- if (fieldMode!=1){
- sql = "SELECT * FROM (" + sql + " UNION SELECT DISTINCT "
- + searchParts[2] + " AS name, creatorID || '-1' AS creatorID"
- + fromSQL + ") GROUP BY name";
- }
-
- sql += " ORDER BY name";
- }
-
- var rows = this._zotero.DB.query(sql, sqlParams);
- for each(var row in rows){
- results.push(row['name']);
- comments.push(row['creatorID'])
- }
- break;
-
- case 'dateModified':
- case 'dateAdded':
- var sql = "SELECT DISTINCT DATE(" + searchParam + ", 'localtime') FROM items "
- + "WHERE " + searchParam + " LIKE ? ORDER BY " + searchParam;
- var results = this._zotero.DB.columnQuery(sql, searchString + '%');
- break;
-
- case 'accessDate':
- var fieldID = this._zotero.ItemFields.getID('accessDate');
-
- var sql = "SELECT DISTINCT DATE(value, 'localtime') FROM itemData "
- + "WHERE fieldID=? AND value LIKE ? ORDER BY value";
- var results = this._zotero.DB.columnQuery(sql, [fieldID, searchString + '%']);
- break;
-
- default:
- var sql = "SELECT fieldID FROM fields WHERE fieldName=?";
- var fieldID = this._zotero.DB.valueQuery(sql, {string:searchParam});
-
- if (!fieldID){
- this._zotero.debug("'" + searchParam + "' is not a valid autocomplete scope", 1);
- var results = [];
- var resultCode = Ci.nsIAutoCompleteResult.RESULT_IGNORED;
- break;
- }
-
- // We don't use date autocomplete anywhere, but if we're not
- // disallowing it altogether, we should at least do it right and
- // use the user part of the multipart field
- var valueField = searchParam=='date' ? 'SUBSTR(value, 12, 100)' : 'value';
-
- var sql = "SELECT DISTINCT " + valueField
- + " FROM itemData NATURAL JOIN itemDataValues "
- + "WHERE fieldID=?1 AND " + valueField
- + " LIKE ?2 "
-
- var sqlParams = [fieldID, searchString + '%'];
- if (extra){
- sql += "AND value NOT IN (SELECT value FROM itemData "
- + "NATURAL JOIN itemDataValues WHERE fieldID=?1 AND itemID=?3) ";
- sqlParams.push(extra);
- }
- sql += "ORDER BY value";
- var results = this._zotero.DB.columnQuery(sql, sqlParams);
- }
-
- if (!results || !results.length){
- var results = [];
- var resultCode = Ci.nsIAutoCompleteResult.RESULT_NOMATCH;
- }
- else if (typeof resultCode == 'undefined'){
- var resultCode = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
- }
-
- var result = new ZoteroAutoCompleteResult(searchString,
- resultCode, 0, "", results, comments);
-
- listener.onSearchResult(this, result);
- }
-
-
- ZoteroAutoComplete.prototype.stopSearch = function(){
- //this._zotero.debug('Stopping autocomplete search');
- }
-
-
- ZoteroAutoComplete.prototype.QueryInterface = function(iid){
- if (!iid.equals(Ci.nsIAutoCompleteSearch) &&
- !iid.equals(Ci.nsIAutoCompleteObserver) &&
- !iid.equals(Ci.nsISupports)){
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
- return this;
- }
-
-
-
- //
- // XPCOM goop
- //
- var ZoteroAutoCompleteFactory = {
- createInstance: function(outer, iid){
- if (outer != null){
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
- return new ZoteroAutoComplete().QueryInterface(iid);
- }
- };
-
-
- var ZoteroAutoCompleteModule = {
- _firstTime: true,
-
- registerSelf: function(compMgr, fileSpec, location, type){
- if (!this._firstTime){
- throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
- }
- this._firstTime = false;
-
- compMgr =
- compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-
- compMgr.registerFactoryLocation(ZOTERO_AC_CID,
- ZOTERO_AC_CLASSNAME,
- ZOTERO_AC_CONTRACTID,
- fileSpec,
- location,
- type);
- },
-
- unregisterSelf: function(compMgr, location, type){
- compMgr =
- compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
- compMgr.unregisterFactoryLocation(ZOTERO_AC_CID, location);
- },
-
- getClassObject: function(compMgr, cid, iid){
- if (!cid.equals(ZOTERO_AC_CID)){
- throw Components.results.NS_ERROR_NO_INTERFACE;
- }
- if (!iid.equals(Components.interfaces.nsIFactory)){
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- }
- return ZoteroAutoCompleteFactory;
- },
-
- canUnload: function(compMgr){ return true; }
- };
-
- function NSGetModule(comMgr, fileSpec){ return ZoteroAutoCompleteModule; }
-